﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Windows;

namespace Yang
{
    public class Block
    {
        public int ID { get; set; }
        public int Level { get; set; }
        public List<Block> Upper { get; set; } = new List<Block>();

        public List<Block> Lower { get; set; } = new List<Block>();

        public Rectangle Area { get; set; }
        public int BlockType { get; set; }
        public string BlockName { 
            get {
                var rv = "";
                switch (BlockType)
                {
                    case 1:rv = "小草";break;
                    case 2: rv = "萝卜"; break;
                    case 3: rv = "玉米"; break;
                    case 4: rv = "耙子"; break;
                    case 5: rv = "树桩"; break;
                    case 6: rv = "白球"; break;
                    case 7: rv = "手套"; break;
                    case 8: rv = "白菜"; break;
                    case 9: rv = "紫球"; break;
                    case 10: rv = "奶瓶"; break;
                    case 11: rv = "火苗"; break;
                    case 12: rv = "刷子"; break;
                    case 13: rv = "剪刀"; break;
                    case 14: rv = "稻草"; break;
                    case 15: rv = "水盆"; break;
                    case 16: rv = "铃铛"; break;
                    default:
                        break;
                }
                return rv;
            } 
        }

        public int Region { get; set; }

        public Block()
        {

        }

        public Block(bool visiable,List<Block>? uppblocks=null)
        {
            this.Visiable = visiable;
            this._UpperBlocks = uppblocks;
        }
        public Block(List<Block> existBlocks)
        {
            ID = existBlocks.Count + 1;
        }
        public string Info
        {
            get
            {
                return $"{ID},{BlockName},x={Area.X},y={Area.Y},level={Level}";
            }
        }

        [JsonIgnore]
        public bool Visiable { get;  set; } = true;
        [JsonIgnore]
        public string ImgPath
        {
            get
            {
                return $"{Game._basePath}Imgs\\{BlockType}.bmp";
            }
        }

        public int VisiableLevel
        {
            get
            {
                if (Upper.Any(x => x.Visiable == true))
                {
                    return Upper[0].VisiableLevel+1;
                }
                else
                {
                    return 0;
                }
         }
        }

        public int VisiableSteps
        {
            get
            {
                return UpperVisiableBlocks.Count;
            }
        }

        private int? _allLowers;
        [JsonIgnore]
        public int AllLowers
        {
            get
            {
                if(_allLowers == null)
                {
                    _allLowers = GetAllLowers().Count;
                }
                return _allLowers.Value;
            }
            set
            {
                _allLowers = value;
            }
        }

        [JsonIgnore]
        public List<Block> UpperVisiableBlocks
        {
            get
            {
                return UpperBlocks.Where(x => x.Visiable == true).ToList();
            }
        }

        private List<Block>? _UpperBlocks = null;
        [JsonIgnore]
        public List<Block> UpperBlocks
        {
            get
            {
                if (_UpperBlocks == null)
                {
                    _UpperBlocks = GetUpperBlocks();
                }
                return _UpperBlocks;
            }
            set
            {
                _UpperBlocks = value;
            }
        }


        private List<Block> GetUpperVisiableBlocks()
        {
            List<Block> upperVisiableBlocks = new List<Block>();
            var up = this.Upper.Where(x =>  x.Visiable == true).ToList();
            foreach (var block in up)
            {
                upperVisiableBlocks.Add(block);
            }
            foreach (var block in up)
            {
                upperVisiableBlocks.AddRange(block.GetUpperVisiableBlocks());
            }
            var rv = upperVisiableBlocks.GroupBy(x => x.ID).Select(x => x.First()).ToList();
            return rv;
        }

        public List<Block> GetUpperBlocks()
        {
            List<Block> upperBlocks = new List<Block>();
            var up = this.Upper.ToList();
            foreach (var block in up)
            {
                upperBlocks.Add(block);
            }
            foreach (var block in up)
            {
                upperBlocks.AddRange(block.GetUpperBlocks());
            }
            var rv = upperBlocks.GroupBy(x => x.ID).Select(x => x.First()).ToList();
            return rv;
        }

        public List<Block> GetAllLowers()
        {
            List<Block> lowers = new List<Block>();
            foreach (var item in this.Lower)
            {
                lowers.Add(item);
                lowers.AddRange(item.GetAllLowers());
            }
            var rv = lowers.GroupBy(x => x.ID).Select(x => x.First()).ToList();
            return rv;
        }

        public void SetVisiable(bool visibable)
        {
            this.Visiable = visibable;
        }
    }

    public static class BlockExtension
    {
        public static List<Block> Clone(this List<Block> history)
        {
            List<Block> his = new List<Block>();
            foreach (var h in history)
            {
                his.Add(new Block(h.Visiable,null)
                {
                    Area = h.Area,
                    BlockType = h.BlockType,
                    ID = h.ID,
                    Level = h.Level,
                    AllLowers = h.AllLowers
                });
            }
            foreach (var h in history)
            {
                var upids = h.Upper.Select(x => x.ID);
                var f = his.Find(x => x.ID == h.ID);
                if (f != null)
                {
                    f.Upper = his.Where(x => upids.Contains(x.ID)).ToList();
                }
            }
            foreach (var h in history)
            {
                var upperallids = h.UpperBlocks.Select(x => x.ID);
                var f = his.Find(x => x.ID == h.ID);
                if (f != null)
                {
                    f.UpperBlocks = his.Where(x => upperallids.Contains(x.ID)).ToList();
                }
            }

            foreach (var h in history)
            {
                var lowerids = h.Lower.Select(x => x.ID);
                var f = his.Find(x => x.ID == h.ID);
                if (f != null)
                {
                    f.Lower = his.Where(x => lowerids.Contains(x.ID)).ToList();
                }
            }

            return his;
        }

    }
}
